package com.friddle.instance.aliyun;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;

import com.aliyun.api.AliyunClient;
import com.aliyun.api.AliyunRequest;
import com.aliyun.api.AliyunResponse;
import com.aliyun.api.DefaultAliyunClient;
import com.aliyun.api.ecs.ecs20140526.request.CreateInstanceRequest;
import com.aliyun.api.ecs.ecs20140526.request.DeleteInstanceRequest;
import com.aliyun.api.ecs.ecs20140526.request.DescribeImagesRequest;
import com.aliyun.api.ecs.ecs20140526.request.DescribeInstanceTypesRequest;
import com.aliyun.api.ecs.ecs20140526.request.DescribeInstancesRequest;
import com.aliyun.api.ecs.ecs20140526.request.DescribeRegionsRequest;
import com.aliyun.api.ecs.ecs20140526.request.DescribeSecurityGroupsRequest;
import com.aliyun.api.ecs.ecs20140526.response.CreateInstanceResponse;
import com.aliyun.api.ecs.ecs20140526.response.DeleteInstanceResponse;
import com.aliyun.api.ecs.ecs20140526.response.DescribeImagesResponse;
import com.aliyun.api.ecs.ecs20140526.response.DescribeInstancesResponse;
import com.aliyun.api.ecs.ecs20140526.response.DescribeSecurityGroupsResponse;
import com.friddle.instance.Instance;
import com.friddle.instance.aliyun.Constants;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.taobao.api.ApiException;

/**
 * Created by friddle on 15-2-28.
 */
public class AliInstance implements Instance {
	private AliyunClient client;
	private AliConfigure configure = new AliConfigure();
	private Map<String, Instance> instances;

	public class AliConfigure {
		public String accessKey;
		public String accessSecret;
		public String aliUrl = "http://ecs.aliyuncs.com";
		public String password = "A1234567890";
		public String regionId = "cn-qingdao";
		public String imageId = "m-28no8fg80";
		public String instanceName = "spider";
	}

	@Override
	public MutablePair<Boolean, String> initEnvironment(String AccessKey, String AccessSecret, Map<String, String> envs) {
		MutablePair<Boolean, String> result = new MutablePair<>();
		configure.accessKey = AccessKey;
		configure.accessSecret = AccessSecret;
		if (envs != null && envs.containsKey(Constants.AliUrl)) {
			configure.aliUrl = envs.get(Constants.AliUrl);
		}
		client = new DefaultAliyunClient(configure.aliUrl, configure.accessKey, configure.accessSecret);
		return result;
	}

	/**
	 * @param type
	 *            <p>
	 *            type 意味Region,型号
	 *            </p>
	 * @param infos
	 *            <p>
	 *            contains lot's of infomation of the types
	 *            </p>
	 *            <table>
	 *            <td>regionId
	 *            <td></td>区域地址</td>
	 *            <td>默认是青岛</td>
	 *            <tr>
	 *            <td>imageId
	 *            <td></td>镜像id</td>
	 *            <td>默认是Ubuntu</td>
	 *            <tr>
	 *            <td>instanceName</td>
	 *            <td>机器的名字</td>
	 *            <td>默认无</td>
	 *            <tr>
	 *            <td>password</td>
	 *            <td>用户密码</td>
	 *            <td>默认123
	 *            <td>
	 *            </tr>
	 *            </table>
	 * @return 成功返回True和InstanceId。失败返回False和失败原因
	 */
	@Override
	public MutablePair<Boolean, Map<String, String>> createInstances(String type, Map<String, String> infos) {
		MutablePair<Boolean, Map<String, String>> result = new MutablePair<Boolean, Map<String, String>>();
		CreateInstanceRequest request = new CreateInstanceRequest();
		request.setInstanceType(type);
		request.setRegionId(infos.get("regionId") != null ? infos.get("regionId") : configure.regionId);
		request.setImageId(infos.get("imageId") != null ? infos.get("imageId") : configure.imageId);
		request.setInstanceName(infos.get("instanceName") != null ? infos.get("instanceName") : configure.instanceName);
		request.setPassword(infos.get("password") != null ? infos.get("password") : configure.password);
		Map<String, String> answer = new HashMap<String, String>();
		try {
			Iterator<String> iterable = this.getSecurityGroup(infos.get("regionId") != null ? infos.get("regionId") : configure.regionId)
					.keySet().iterator();
			request.setSecurityGroupId(iterable.next());
			CreateInstanceResponse response = client.execute(request);
			if (!StringUtils.isEmpty(response.getErrorCode())) {
				throw new ApiException(response.getMessage());
			}
			JsonParser mParse = new JsonParser();
			mParse.parse(response.getBody()).getAsJsonObject().toString();
			result.setLeft(true);
			result.setRight(answer);
		} catch (ApiException e) {
			result.setLeft(false);
			answer.put("ErrMsg", e.getErrMsg());
			answer.put("ErrCode", e.getErrCode());
			result.setRight(answer);
			return result;
		}
		return null;
	}

	public HashMap<String, Map<String, String>> getSecurityGroup(String RegionId) throws ApiException {
		DescribeSecurityGroupsRequest request = new DescribeSecurityGroupsRequest();
		request.setRegionId(RegionId);
		DescribeSecurityGroupsResponse response = client.execute(request);
		JsonParser mParse = new JsonParser();
		JsonArray groups = mParse.parse(response.getBody()).getAsJsonObject().getAsJsonObject("SecurityGroups")
				.getAsJsonArray("SecurityGroup");
		HashMap<String, Map<String, String>> values = new HashMap<>();
		for (int i = 0; i < groups.size(); i++) {
			values.put(groups.get(i).getAsJsonObject().get("SecurityGroupId").getAsString(), null);
		}
		return values;
	}

	/**
	 * <p>
	 * 通过InstanceId删除机器
	 * </p>
	 * 
	 * @param instanceid
	 *            <p>
	 *            机器的id
	 *            </p>
	 * @return 成功返回True和Null。失败返回False和错误的原因
	 */
	@Override
	public MutablePair<Boolean, String> deleteInstances(String instanceid) {
		MutablePair<Boolean, String> result = new MutablePair<>();
		DeleteInstanceRequest request = new DeleteInstanceRequest();
		request.setInstanceId(instanceid);
		try {
			DeleteInstanceResponse response = client.execute(request);
			if (!StringUtils.isEmpty(response.getErrorCode())) {
				throw new ApiException(response.getMessage());
			}
			result.setLeft(true);
			result.setRight(response.getBody());
		} catch (ApiException e) {
			result.setLeft(false);
			result.setRight(e.getErrMsg());
		}
		return result;
	}

	/**
	 * 
	 * @return
	 * @throws ApiException
	 */
	public String getInformationOfAlis() {
		HashMap<String, String> map = new HashMap<String, String>();
		AliyunRequest request = new DescribeInstanceTypesRequest();
		AliyunResponse response = null;
		try {
			response = client.execute(request);
			map.put("InstanceType", response.getBody());
			request = new DescribeRegionsRequest();
			response = client.execute(request);
			map.put("Region", response.getBody());
		} catch (ApiException e) {
			return e.getMessage();
		}
		Gson mGson = new Gson();
		String info = mGson.toJson(map);
		return info;
	}

	public String getImageOfAliInstances() {
		DescribeImagesRequest imageRequest = new DescribeImagesRequest();
		imageRequest.setRegionId(configure.regionId);
		DescribeImagesResponse response = null;
		try {
			response = client.execute(imageRequest);
			return response.getMessage();
		} catch (ApiException e) {
			return e.getMessage();
		}
	}

	@Override
	public Map<String, Map<String, String>> getInstancesDescribe(Map<String, String> variables) {
		Map<String, Map<String, String>> infos = new HashMap<String, Map<String, String>>();
		try {
			if (variables == null)
				variables = new HashMap<>();
			String regionId = (variables.get("regionId") != null) ? variables.get("regionId") : configure.regionId;
			DescribeInstancesRequest request = new DescribeInstancesRequest();
			request.setRegionId(regionId);
			if (variables.get("InstanceId") != null)
				request.setInstanceIds(variables.get("InstanceId"));
			DescribeInstancesResponse response = client.execute(request);
			JsonParser parse = new JsonParser();
			JsonArray instance = parse.parse(response.getBody()).getAsJsonObject().getAsJsonObject("Instances").getAsJsonArray("Instance");
			for (int i = 0; i < instance.size(); i++) {
				JsonObject object = instance.get(i).getAsJsonObject();
				HashMap<String, String> map = new HashMap<>();
				map.put("HostName", object.get("HostName").getAsString());
				map.put("InstanceName", object.get("InstanceName").getAsString());
				map.put("RegionId", object.get("RegionId").getAsString());
				map.put("Status", object.get("Status").getAsString());
				map.put("InstanceType", object.get("InstanceType").getAsString());
				map.put("PublicIpAddress", object.getAsJsonObject("PublicIpAddress").get("IpAddress").getAsString());
				map.put("InnerIpAddress", object.getAsJsonObject("InnerIpAddress").get("IpAddress").getAsString());
				infos.put(object.get("InstanceId").getAsString(), map);
			}
			return infos;
		} catch (ApiException e) {
			e.printStackTrace();
			return infos;
		}
	}
}
